package com.xiaoyu.lanling.widget.photo

import `in`.srain.cube.concurrent.AppThreads
import `in`.srain.cube.util.LocalDisplay
import android.annotation.SuppressLint
import android.app.Activity
import android.content.DialogInterface
import android.graphics.Bitmap
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog
import androidx.emoji.widget.EmojiTextView
import androidx.viewpager.widget.PagerAdapter
import com.facebook.datasource.BaseDataSubscriber
import com.facebook.datasource.DataSource
import com.facebook.datasource.DataSubscriber
import com.facebook.drawee.backends.pipeline.Fresco
import com.xiaoyu.base.image.ImageLoadInfo
import com.xiaoyu.base.image.ImageUrlManager
import com.xiaoyu.base.utils.extensions.getViewTag
import com.xiaoyu.base.utils.extensions.setOnClickDebounceListener
import com.xiaoyu.base.utils.extensions.setViewTag
import com.xiaoyu.base.utils.upload.UploadImageOriginalType
import com.xiaoyu.lanling.R
import com.xiaoyu.lanling.media.image.ImageLoadParam
import com.xiaoyu.lanling.media.image.ImageViewUtil.loadImage
import frescoextra.DoubleTapGestureListener
import frescoextra.GestureListenerWrapper
import frescoextra.MultiGestureListener
import frescoextra.ZoomableDraweeView
import java.util.*

class PhotoPagerAdapter internal constructor(private val mContext: Activity?) : PagerAdapter() {

    private val viewHolderMap: MutableMap<String, ViewHolder> = HashMap()
    private val dialogItems = arrayOf("保存到本地")

    private var mImageUrlList: List<String> = ArrayList()

    private val mOnClickListener = View.OnClickListener { v: View ->
        val url: String = v.getViewTag<String>(VIEW_TAG_URL) ?: return@OnClickListener
        val thumbnailLoadParam: ImageLoadParam = v.getViewTag<ImageLoadParam>(VIEW_TAG_THUMBNAIL)
                ?: return@OnClickListener
        loadImageFromNetwork(url, thumbnailLoadParam, true)
        v.visibility = View.GONE
    }

    fun setData(imageUrlList: List<String>?) {
        mImageUrlList = imageUrlList ?: emptyList()
        notifyDataSetChanged()
    }

    override fun getCount(): Int {
        return if (mImageUrlList.isEmpty()) {
            0
        } else mImageUrlList.size
    }

    @SuppressLint("InflateParams")
    override fun instantiateItem(container: ViewGroup, position: Int): Any {
        return try {
            val view = LayoutInflater.from(container.context).inflate(R.layout.view_photo_pager, null, false)
            val imageView: ZoomableDraweeView = view.findViewById(R.id.image_view)
            val originalButton: EmojiTextView = view.findViewById(R.id.original_button)

            originalButton.text = "查看原图"
            addGestureListener(imageView, position)
            container.addView(view, ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)

            val url = mImageUrlList[position]
            val viewHolder = ViewHolder(imageView, originalButton)
            viewHolderMap[url] = viewHolder

            val imageLoadInfo = ImageLoadInfo(url)
            val hasOriginal = imageLoadInfo.originalType == UploadImageOriginalType.ORIGINAL

            loadImage(url)
            originalButton.visibility = if (hasOriginal) View.VISIBLE else View.GONE
            originalButton.setOnClickDebounceListener(mOnClickListener)
            originalButton.setViewTag(VIEW_TAG_URL, url)
            view
        } catch (e: Exception) {
            super.instantiateItem(container, position)
        }
    }

    private fun loadImage(url: String?) {
        val viewHolder = viewHolderMap[url] ?: return
        val thumbnailLoadParam = getThumbnailLoadParam(url)
        viewHolder.originalButton.setViewTag(VIEW_TAG_THUMBNAIL, thumbnailLoadParam)

        val imageUri = getTempLoadParam(url).uri
        val imagePipeline = Fresco.getImagePipeline()
        val hasMemoryCache = imagePipeline.isInBitmapMemoryCache(imageUri)
        if (hasMemoryCache) {
            loadImageFromCache(url, thumbnailLoadParam)
            return
        }
        val subscriber: DataSubscriber<Boolean> = object : BaseDataSubscriber<Boolean>() {
            override fun onNewResultImpl(dataSource: DataSource<Boolean>) {
                if (!dataSource.isFinished) {
                    return
                }
                val isInCache = dataSource.result
                if (isInCache != null && isInCache) {
                    loadImageFromCache(url, thumbnailLoadParam)
                } else {
                    loadImageFromNetwork(url, thumbnailLoadParam, false)
                }
            }

            override fun onFailureImpl(dataSource: DataSource<Boolean>) {
                loadImageFromNetwork(url, thumbnailLoadParam, false)
            }
        }
        val inDiskCacheSource = imagePipeline.isInDiskCache(imageUri)
        inDiskCacheSource.subscribe(subscriber, AppThreads.getMainExecutor())
    }

    private fun loadImageFromNetwork(url: String?, thumbnailLoadParam: ImageLoadParam, keepOriginal: Boolean) {
        val viewHolder = viewHolderMap[url] ?: return
        val originalLoadParam = getOriginalLoadParam(url, thumbnailLoadParam, keepOriginal)
        loadImage(viewHolder.imageView, originalLoadParam)
    }

    private fun loadImageFromCache(url: String?, thumbnailLoadParam: ImageLoadParam) {
        val viewHolder = viewHolderMap[url] ?: return
        val loadParam = getOriginalLoadParam(url, thumbnailLoadParam, true)
        loadImage(viewHolder.imageView, loadParam)
        viewHolder.originalButton.visibility = View.GONE
    }

    // Just want get the original image url which has been formatted. Why don't use "url" directly? Because we'll convert https to http.
    private fun getTempLoadParam(url: String?): ImageLoadParam {
        return ImageLoadParam.newBuilder()
                .setUrl(url)
                .setWidthToFullScreen()
                .setHeightToFullScreen()
                .setMaxBitmapSize(Int.MAX_VALUE)
                .setKeepOriginal(true)
                .setAutoPlay(true)
                .build()
    }

    private fun getThumbnailLoadParam(url: String?): ImageLoadParam {
        val thumbnailHeight = getHeightInPXForThumbnail(mImageUrlList.size)
        val thumbnailWidth = getWidthInPXForThumbnail(mImageUrlList, url, thumbnailHeight)
        return ImageLoadParam.newBuilder()
                .setUrl(url)
                .setWidth(thumbnailWidth)
                .setHeight(thumbnailHeight)
                .setAutoPlay(true)
                .build()
    }

    private fun getOriginalLoadParam(url: String?, thumbnailLoadParam: ImageLoadParam, keepOriginal: Boolean): ImageLoadParam {
        return ImageLoadParam.newBuilder()
                .setUrl(url)
                .setWidth(LocalDisplay.SCREEN_WIDTH_PIXELS)
                .setHeight(LocalDisplay.SCREEN_HEIGHT_PIXELS)
                .setProgressiveRenderingEnabled(true)
                .setBitmapConfig(if (keepOriginal) Bitmap.Config.ARGB_8888 else null)
                .setLocalThumbnailPreviewsEnabled(true)
                .setLowResImageLoadParam(thumbnailLoadParam)
                .setAutoPlay(true)
                .setMaxBitmapSize(Int.MAX_VALUE)
                .setKeepOriginal(keepOriginal)
                .build()
    }

    private fun addGestureListener(originalImageView: ZoomableDraweeView, position: Int) {
        val gestureListener = MultiGestureListener()
        gestureListener.addListener(object : GestureListenerWrapper() {
            override fun onLongPress(e: MotionEvent) {
                showDialog(position)
                super.onLongPress(e)
            }

            override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
                mContext?.finish()
                return false
            }
        })
        gestureListener.addListener(DoubleTapGestureListener(originalImageView))
        originalImageView.setIsLongpressEnabled(true)
        originalImageView.setTapListener(gestureListener)
    }

    override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
        try {
            container.removeView(`object` as View)
        } catch (e: Exception) {
            super.destroyItem(container, position, `object`)
        }
    }

    override fun isViewFromObject(view: View, `object`: Any): Boolean {
        return view === `object`
    }

    private fun showDialog(position: Int) {
        if (mContext == null || mContext.isFinishing || mContext.isDestroyed) {
            return
        }
        if (position < 0 || mImageUrlList.isEmpty()) {
            return
        }
        val isLocal = ImageUrlManager.getInstance().isLocalUrl(mImageUrlList[position])
        // TODO (Temp for add the share function)
        if (isLocal) {
            return
        }
        AlertDialog.Builder(mContext)
                .setItems(dialogItems) { dialog: DialogInterface, which: Int ->
                    when (which) {
                        0 -> PhotoUtils.saveImageFromUrl(mImageUrlList[position])
                    }
                    dialog.dismiss()
                }.show()
    }

    private fun getHeightInPXForThumbnail(listSize: Int): Int {
        return when (listSize) {
            1 -> GRID_ITEM_SIZE_WITH_PX_FOR_ONE
            2 -> GRID_ITEM_SIZE_WITH_PX_FOR_ONE_ROW_FOR_TWO
            else -> GRID_ITEM_SIZE_WITH_PX_FOR_ONE_ROW
        }
    }

    private fun getWidthInPXForThumbnail(imageUrlList: List<String?>?, imageUrl: String?, itemHeight: Int): Int {
        return if (imageUrlList!!.size == 1) {
            val loadInfo = ImageLoadInfo(imageUrl)
            if (loadInfo.ratio < 0.75f) {
                (GRID_ITEM_SIZE_WITH_PX_FOR_ONE * 0.75f).toInt()
            } else if (loadInfo.ratio < 1) {
                (GRID_ITEM_SIZE_WITH_PX_FOR_ONE * loadInfo.ratio).toInt()
            } else {
                GRID_ITEM_SIZE_WITH_PX_FOR_ONE
            }
        } else {
            itemHeight
        }
    }

    private class ViewHolder internal constructor(val imageView: ZoomableDraweeView, val originalButton: EmojiTextView)

    companion object {
        private const val VIEW_TAG_URL = 1
        private const val VIEW_TAG_THUMBNAIL = 2

        val GRID_SIZE_WITH_PX_FOR_ONE: Int = LocalDisplay.dp2px(200f)
        val GRID_WIDTH_WITH_PX_FOR_MORE: Int = LocalDisplay.SCREEN_WIDTH_PIXELS - LocalDisplay.dp2px(16 + 16.toFloat())
        val GRID_ITEM_SIZE_WITH_PX_FOR_ONE = GRID_SIZE_WITH_PX_FOR_ONE
        val GRID_ITEM_SIZE_WITH_PX_FOR_ONE_ROW_FOR_TWO: Int = (GRID_WIDTH_WITH_PX_FOR_MORE - LocalDisplay.dp2px(2 + 2.toFloat())) / 2
        val GRID_ITEM_SIZE_WITH_PX_FOR_ONE_ROW: Int = (GRID_WIDTH_WITH_PX_FOR_MORE - LocalDisplay.dp2px(2 * 2 + 2.toFloat())) / 3
    }

}